package oralExamSchedulingSystem;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Scanner;

import entity.Class;
import entity.Group;
import entity.Room;
import entity.Student;
import entity.TimeSlot;
import graph.Graph;
import graph.Vertex;

// TODO: Auto-generated Javadoc
/**
 * The Class IO.
 */
public class IO {

	/**
	 * Get a single input without space from console.
	 *
	 * @param inputInfo the input info
	 * @return the input
	 */
	private Scanner getInput(String inputInfo) {

		System.out.println(inputInfo + ": ");
		Scanner scanner = new Scanner(System.in);
		return scanner;
	}

	/**
	 * Get a line input from console.
	 *
	 * @param inputInfo the input info
	 * @return the line input
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	private String getLineInput(String inputInfo) throws IOException {

		System.out.println(inputInfo + ": ");

		InputStreamReader converter = new InputStreamReader(System.in);
		BufferedReader in = new BufferedReader(converter);
		return in.readLine();
	}

	/**
	 * Gets the reporting room number.
	 *
	 * @return the reporting room number
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public String getReportingRoomNumber() throws IOException {
		return getLineInput("Input the Reporting Room Number");
	}

	/**
	 * Gets the academic year.
	 *
	 * @return the academic year
	 */
	public String getAcademicYear() {
		return getInput("Input the Academic Year").next();
	}

	/**
	 * Gets the semester.
	 *
	 * @return the semester
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public String getSemester() throws IOException {
		String input=getInput("Input the Semester([1]-First Term   [2]-Second Term   [3]-Mock Exam)").next();
			if(input.equals("1")){
				input="First Term";
			}
			else if(input.equals("2")){
				input="Second Term";
			}
			else if(input.equals("3")){
				input="Mock Exam";
			}
			else{
				System.out.println("Invalid input!");
				return getSemester();
			}
		
		return input;
	}

	/**
	 * Gets the date.
	 *
	 * @return the date
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public String getDate() throws IOException {
		String input=getLineInput("Input the Exam Date(DDMMYYYY)");
		if (input.length()!=8){
			System.out.println("Invalid input!");
			return getDate();
		}
		try{
			int dd=Integer.parseInt(input.substring(0, 2));
			int mm=Integer.parseInt(input.substring(2, 4));
			int yyyy=Integer.parseInt(input.substring(4, 8));
			if (yyyy<1000){
				System.out.println("Invalid input!");
				return getDate();
			}
			if (mm<0 || mm>12){
				System.out.println("Invalid input!");
				return getDate();
			}
			int maxDay;
			switch (mm){
			case 1:
			case 3:
			case 5:
			case 7:
			case 8:
			case 10:
			case 12: maxDay=31; break;
			case 4:
			case 6:
			case 9:
			case 11: maxDay=30; break;
			case 2: 
				if ((yyyy % 4 == 0) && (yyyy % 100 != 0) || (yyyy % 400 == 0)){
					maxDay=29;
				}else{
					maxDay=28;
				}
				break;
			default: maxDay=0;
			}
			if (dd<0 || dd>maxDay){
				System.out.println("Invalid input!");
				return getDate();
			}
			input=input.substring(0, 2)+"/"+input.substring(2, 4)+"/"+input.substring(4, 8)+"(DD/MM/YYYY)";
		}catch (Exception e){
			System.out.println("Invalid input!");
			return getDate();
		}
		return input;
	}
	
	/**
	 * Gets the level.
	 *
	 * @return the level
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public String getLevel() throws IOException {
		String input= getLineInput("Input the Level(1-6)");
		if(input.length()!=1){
			System.out.println("Invalid input!");
			return getLevel();
		}
		try{
			int lv=Integer.parseInt(input);
			switch (lv){
			case 1: input="Form 1"; break;
			case 2: input="Form 2"; break;
			case 3: input="Form 3"; break;
			case 4: input="Form 4"; break;
			case 5: input="Form 5"; break;
			case 6: input="Form 6"; break;
			default:
				System.out.println("Invalid input!");
				return getLevel();
			}
		}catch (Exception e){
			System.out.println("Invalid input!");
			return getLevel();
		}
		return input;
	}

	/**
	 * Gets the number of subjects.
	 *
	 * @return the number of subjects
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public int getNumberOfSubjects() throws IOException {
		try {
			int input;
			do {
				input = Integer.parseInt(getInput(
						"Input the Number of Subjects(1-2)").next());
				if (input < 1 || input > 2) {
					System.out.println("Invalid input!");
				}
			} while (input < 1 || input > 2);
			return input;
		} catch (Exception e) {
			System.out.println("Invalid input!");
			return getNumberOfSubjects();
		}
	}

	/**
	 * Gets the group size.
	 *
	 * @return the group size
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public int getGroupSize() throws IOException {
		try {
			int input;
			int minGroupSize = 3;
			do {
				input = Integer.parseInt(getInput("Input the Group Size(>=3)")
						.next());
				if (input < minGroupSize) {
					System.out.println("Invalid input!");
				}
			} while (input < minGroupSize);
			return input;
		} catch (Exception e) {
			System.out.println("Invalid input!");
			return getGroupSize();
		}
	}

	/**
	 * Gets the duration in minutes.
	 *
	 * @return the duration
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public int getDuration() throws IOException {
		try {
			int input;
			do {
				input = Integer.parseInt(getInput(
						"Input the Duration in minutes(5-30)").next());
				if (input < 5 || input > 30) {
					System.out.println("Invalid input!");
				}
			} while (input < 5 || input > 30);
			return input;
		} catch (Exception e) {
			System.out.println("Invalid input!");
			return getNumberOfRoom();
		}
	}

	/**
	 * Gets the number of room.
	 *
	 * @return the number of room
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public int getNumberOfRoom() throws IOException {
		int numberOfRoom=0;
		try {
			String input = getLineInput("Input the Number of Rooms");
			numberOfRoom = Integer.parseInt(input);
			if (numberOfRoom<1){
				System.out.println("Invalid input!");
				return getNumberOfRoom();
			}
		} catch (Exception e) {
			System.out.println("Invalid input!");
			return getNumberOfRoom();
		}
		return numberOfRoom;
	}

	/**
	 * Gets the room numbers.
	 *
	 * @param numRoom the number of rooms
	 * @return the room numbers
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public ArrayList<String> getRoomNumbers(int numRoom) throws IOException {

		Scanner receivedStrings = getInput("Input the Room Numbers");

		ArrayList<String> roomNumbers = new ArrayList<String>();

		for (int i = 0; i < numRoom; i++) {
			roomNumbers.add(receivedStrings.next());
		}

		return roomNumbers;
	}

	/**
	 * Gets the starting time.
	 *
	 * @return the starting time
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public String getStartingTime() throws IOException {
		String input = getLineInput("Input the Starting Time(hh:mm)");
		
		int dummyIndex=input.indexOf(':');
		if (dummyIndex<0 || input.length()<3){
			System.out.println("Invalid input!");
			return getStartingTime();
		}
		try{
			int hh=Integer.parseInt(input.substring(0, dummyIndex));
			int mm=Integer.parseInt(input.substring(dummyIndex+1, input.length()));
			if (hh<0||hh>23||mm<0||mm>59){
				System.out.println("Invalid input!");
				return getStartingTime();
			}
		}catch (Exception e){
			System.out.println("Invalid input!");
			return getStartingTime();
		}
		return input;
	}

	/**
	 * Gets the subject name.
	 *
	 * @return the subject name
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public String getSubjectName() throws IOException {
		String input = getLineInput("Input the Subject Name([1]-Chinese Language   [2]-English Language)");
		
		if(input.length()!=1){
			System.out.println("Invalid input!");
			return getSubjectName();
		}
		try{
			int subj=Integer.parseInt(input);
			switch (subj){
			case 1: input="Chinese Language"; break;
			case 2: input="English Language"; break;
			default:
				System.out.println("Invalid input!");
				return getSubjectName();
			}
		}catch (Exception e){
			System.out.println("Invalid input!");
			return getSubjectName();
		}
		return input;
	}

	/**
	 * Import student list in csv format.
	 *
	 * @return the student record
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public StudentRecord importCsvStudentList() throws IOException {

		try {
			BufferedReader CSVFile = new BufferedReader(new FileReader(
					getLineInput("Input the CSV File Path")));
			StudentRecord sr = new StudentRecord();
			String dataRow = CSVFile.readLine();
			while (dataRow != null) {
				String[] dataArray = dataRow.split(",");
				// sid, cls, no, name, sex
				Student s = new Student(Integer.parseInt(dataArray[0].trim()),
						Integer.parseInt(dataArray[2].trim()),
						dataArray[3].trim(), dataArray[4].trim().charAt(0));
				Class c = new Class(dataArray[1].trim());
				sr.addStudent(s, c);
				dataRow = CSVFile.readLine(); // Read next line of data.
			}
			// Close the file once all data has been read.
			CSVFile.close();
			return sr;
		} catch (FileNotFoundException e) {
			System.out.println("Invalid path/Wrong content format!");
			return importCsvStudentList();

		}

	}

	/**
	 * Export schedule.
	 *
	 * @param stt the scheduled subject time table
	 */
	public void exportSchedule(SubjectTimeTable stt)
        {
        	try
        	{
        		Graph g=stt.getGraph();
				Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(stt.getAcademicYear()+stt.getSemester()+"_"+stt.getSubjectName()+"_Schedule.csv"), "UTF-8"));
				out.append("Wa Ying College\n");
				out.append("Year "+stt.getAcademicYear()+" "+stt.getSemester()+" Oral Examination Schedule\n");
				out.append("Level:,"+stt.getLevel()+"\n");
				out.append("Subject:,"+stt.getSubjectName()+"\n");
				out.append("Date:,"+stt.getDate()+"\n");
				out.append("Reporting Room:,"+stt.getReportingRoom()+"\n");
				out.append("\n");
				out.append("Class,Class No.,Name,Sex,Reporting Time,Group,Candidate,Exam Room,Time conflicted w/ the first schedule\n");

        	    ArrayList<Vertex> groupVertices = stt.getGroupVertices();

        	    ArrayList<Vertex> StudentVerticesInGroupOrder;
        	    
        	    
        	    // Base on all group in timetable, we print all the student in gorup order
        	    for(Vertex groupVertex : groupVertices){
        	    	
        	    	
        	    	// Get Group Information
        	    	Group groupForThisStudent = (Group)groupVertex.getData();
    	    		int groupId = groupForThisStudent.getGroupId();
    	    		
    	    
    	    		// Get TimeSlot Information
    	    		Vertex timeSlotVertexForThisGroup = g.findVerticsByTypeFromVertex(TimeSlot.class, groupVertex).get(0);
    	    		TimeSlot timeSlotForThisGroup = (TimeSlot)timeSlotVertexForThisGroup.getData();
    	    		String reportingTime = timeSlotForThisGroup.minuteToString(timeSlotForThisGroup.getStartTime());
    	    		
    	    		// Get Room Information
    	    		Vertex roomVertexForThisGroup = g.findVerticsByTypeFromVertex(Room.class, groupVertex).get(0);
    	    		Room roomForThisGroup = (Room)roomVertexForThisGroup.getData();
    	    		String roomNumber = roomForThisGroup.getRoomNumber();
        	    	
        	    	
        	    	
        	    	StudentVerticesInGroupOrder = g.findVerticsByTypeFromVertex(Student.class, groupVertex);
        	    	char candidate;
        	    	if (stt.getSubjectName().contains("Chinese")){
        	    		candidate='1';
        	    	}else{
        	    		candidate='A';
        	    	}
        	    	
        	    	// Base on each group we get print student info of student in that group
        	    	for(Vertex studentVertex : StudentVerticesInGroupOrder){
        	    		
        	    		
        	    		// Check student whether he has overlapped timeSlot
        	    		ArrayList<Vertex> timeSlotsVertexForThisStudent = g.findVerticsByTypeFromVertex(TimeSlot.class, studentVertex);
        	    		String isCollide = "";
        	    		if(timeSlotsVertexForThisStudent.size()>1){
   
        	    			for(Vertex timeSlotVertexForThisStudent :timeSlotsVertexForThisStudent) {
        	    				TimeSlot timeSlot = (TimeSlot)timeSlotVertexForThisStudent.getData();
        	    				for(Vertex nextTimeSlotVertexForThisStudent :timeSlotsVertexForThisStudent) {
        	    					TimeSlot nextTimeSlot = (TimeSlot)nextTimeSlotVertexForThisStudent.getData();
        	    					if(timeSlot!=nextTimeSlot && timeSlot.isCollideWith(nextTimeSlot)) {
        	    						isCollide = "Yes";
        	    						break;
        	    					}
        	    				}
        	    				
        	    			}
        	    		}
        	    		
        	    		        	    		
        	    		// Get Class Information
        	    		Vertex classVertexForThisStudent = g.findVerticsByTypeFromVertex(Class.class, studentVertex).get(0);
        	    		Class classForThisStudent = (Class)classVertexForThisStudent.getData();
        	    		String className = classForThisStudent.getClassName();

        	    		// Get Student Information
        	    		Student student= (Student)studentVertex.getData();
        	    		// int studentId = student.getStudentId();
        	    		int classNumber = student.getClassNumber();
        	    		String name = student.getName();
        	    		char sex = student.getSex();
        	    		out.append(className+","+Integer.toString(classNumber)+","+name+","+sex+","+reportingTime+","+Integer.toString(groupId)+","+candidate+","+roomNumber+","+isCollide+"\n");
        	    		candidate=(char)((int)candidate+1);
        	    	}
        	    	out.append("\n");
        	    }
        	    out.flush();
        	    out.close();
        	    System.out.println("Exported successfully!");
        	}
        	catch(IOException e)
        	{
        	     e.printStackTrace();
        	} 
                
                
        }

	/**
	 * Closing message.
	 */
	public void closingMsg() {
		System.out.println("Thank you for using our system!");
	}
}